library(UCell)
library(ggpubr)
library(Seurat)
library(SeuratDisk)
library(tidyverse)
library(assertthat)
library(cowplot)
library(tidyquant)
library(viridis)
library(EnhancedVolcano)
library(MOFA2)
library(HDF5Array)
library(ComplexHeatmap)
library(circlize)
library(clusterProfiler)
library(SPATA2)
source(file.path("R","functions.R"))
Figure 6e
## subset for tissue resident myeloid cells
gb_mf <- subset(all, subset=celltype_cor %in% c("MG","CAMs","TAMs","Trans. moTAMs") & diagnosis == "GB") #,"MG"
comp_celltype <- case_when(grepl("MG",gb_mf$celltype_cor) ~ "MG",
T ~ paste(gb_mf$celltype_cor,gb_mf$compartment,sep="_"))
names(comp_celltype) <- colnames(gb_mf)
gb_mf$comp_celltype <- comp_celltype
Idents(gb_mf) <- gb_mf$comp_celltype
## create the mofa object
if (!file.exists(file.path("data","mofa_model_gb_myeloid_cells.h5"))) {
## create MOFA object
#DefaultAssay(gb_mf) <- "RNA"
gb_mf <- gb_mf %>% NormalizeData() %>% FindVariableFeatures(nfeatures = 5000) %>% ScaleData()
MOFAobject_all <- create_mofa(gb_mf, groups = "comp_celltype", features = VariableFeatures(gb_mf), assay="RNA", extract_metadata = T)
## plot data overview
plot_data_overview(MOFAobject_all)
## Default data options
data_opts <- get_default_data_options(MOFAobject_all)
## Default model options
model_opts <- get_default_model_options(MOFAobject_all)
## Training options
train_opts <- get_default_training_options(MOFAobject_all)
train_opts$convergence_mode <- "fast"
train_opts$seed <- 42
model_opts$num_factors <- 10
#prepare mofa object
MOFAobject_all <- prepare_mofa(
object = MOFAobject_all,
data_options = data_opts,
model_options = model_opts,
training_options = train_opts
)
## generate a hdf5 file for the output
rhdf5::h5createFile(file.path("data","mofa_model_gb_myeloid_cells.h5"))
## train model
MOFAobject_all <- run_mofa(MOFAobject_all, outfile = file.path("data","mofa_model_gb_myeloid_cells.h5"), use_basilisk = T)
} else {
MOFAobject_all <- load_model(file.path("data","mofa_model_gb_myeloid_cells.h5"))
}
## plot model
plt <- plot_variance_explained(MOFAobject_all, x="view", y="factor") +
geom_text(aes(label=round(value,2))) +
coord_fixed()
plt

## gsea cluster profiler
if (!file.exists(file.path("data","mofa_weights2_>.1_gb_mf.csv"))) {
## gsea cluster profiler
mofa_weights2 <- get_weights(MOFAobject_all, views = "RNA", factors = 1:8,
as.data.frame = TRUE) %>%
group_by(factor) %>%
top_n(100, wt=value)
#filter(value>.1)
## convert gene names
genes <- bitr(unique(mofa_weights2$feature), fromType = "SYMBOL", toType = "ENTREZID", OrgDb = 'org.Hs.eg.db')
colnames(genes)[1] <- "feature"
## comparison between clusters
mofa_weights2 <- mofa_weights2 %>%
left_join(genes[!duplicated(genes$feature),]) %>%
na.omit()
## export mofa_weight2
write.csv(mofa_weights2, file.path("data","mofa_weights2_>.1_gb_mf.csv"))
} else {
mofa_weights2 <- read.csv(file.path("data","mofa_weights2_>.1_gb_mf.csv"), row.names = 1)
}
diff_go_bp <- compareCluster(ENTREZID ~ factor,
data=mofa_weights2,
fun = enrichGO,
OrgDb = 'org.Hs.eg.db',
ont = "BP")
preprocess data for Figure 6j
load(file.path("data","gb_necrosis.RData"))
load(file.path("data","gb_necrosis.RData"))
DefaultAssay(gb_necrosis) <- "Nanostring"
VariableFeatures(gb_necrosis) <- rownames(gb_necrosis)
gb_necrosis <- gb_necrosis %>%
NormalizeData() %>%
ScaleData() %>%
RunPCA()
Performing log-normalization
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
|
| | 0%
|
|======================================================= | 50%
|
|==============================================================================================================| 100%
## classify necrosis cells
if (!file.exists(file.path("data","GBM_1_18_celltype_predictions.RData"))) {
## load annotated references single-nuc-seq dataset
reference <- LoadH5Seurat(file.path("data","reference_seurat.H5Seurat"))
## downsample reference
set.seed(79106)
cell_ids <- reference[[]] %>%
rownames_to_column(var = "cellID") %>%
group_by(celltype_cor) %>%
slice_sample(n=200, replace = T) %>%
distinct(cellID, celltype_cor)
## subset for genes present in the nanostring dataset
reference <- reference[rownames(gb_mvp),cell_ids$cellID]
## remove cells with few counts
reference <- reference[,colSums(reference[["RNA"]]@counts)>10]
## re-normalize
VariableFeatures(reference) <- rownames(reference)
DefaultAssay(reference) <- "RNA"
reference <- reference %>%
NormalizeData() %>%
ScaleData() %>%
RunPCA()
## map celltypes
anchors_necrosis <- FindTransferAnchors(reference = reference , query = gb_necrosis,
dims = 1:30, reference.reduction = "pca")
predictions_necrosis <- TransferData(anchorset = anchors_necrosis, refdata = reference$celltype_cor,
dims = 1:30, k.weight = 20)
## adjust cell labels
predictions_necrosis$predicted.id_cor <- case_when(predictions_necrosis$predicted.id == "Transitory Mo-TAM" ~ "Tr. moTAMs",
grepl("Mo-TAM", predictions_necrosis$predicted.id) ~ "moTAMs",
grepl("TAM", predictions_necrosis$predicted.id) ~ "mgTAMs",
T ~ predictions_necrosis$predicted.id)
save(predictions_necrosis, file = file.path("data","GBM_1_18_celltype_predictions.RData"))
} else {
load(file.path("data","GBM_1_18_celltype_predictions.RData"))
}
## classify necrosis cells
if (!file.exists(file.path("data","GBM_1_18_celltype_predictions.RData"))) {
## load annotated references single-nuc-seq dataset
reference <- LoadH5Seurat(file.path("data","reference_seurat.H5Seurat"))
## downsample reference
set.seed(79106)
cell_ids <- reference[[]] %>%
rownames_to_column(var = "cellID") %>%
group_by(celltype_cor) %>%
slice_sample(n=200, replace = T) %>%
distinct(cellID, celltype_cor)
## subset for genes present in the nanostring dataset
reference <- reference[rownames(gb_mvp),cell_ids$cellID]
## remove cells with few counts
reference <- reference[,colSums(reference[["RNA"]]@counts)>10]
## re-normalize
VariableFeatures(reference) <- rownames(reference)
DefaultAssay(reference) <- "RNA"
reference <- reference %>%
NormalizeData() %>%
ScaleData() %>%
RunPCA()
## map celltypes
anchors_necrosis <- FindTransferAnchors(reference = reference , query = gb_necrosis,
dims = 1:30, reference.reduction = "pca")
predictions_necrosis <- TransferData(anchorset = anchors_necrosis, refdata = reference$celltype_cor,
dims = 1:30, k.weight = 20)
## adjust cell labels
predictions_necrosis$predicted.id_cor <- case_when(predictions_necrosis$predicted.id == "Transitory Mo-TAM" ~ "Tr. moTAMs",
grepl("Mo-TAM", predictions_necrosis$predicted.id) ~ "moTAMs",
grepl("TAM", predictions_necrosis$predicted.id) ~ "mgTAMs",
T ~ predictions_necrosis$predicted.id)
save(predictions_necrosis, file = file.path("data","GBM_1_18_celltype_predictions.RData"))
} else {
load(file.path("data","GBM_1_18_celltype_predictions.RData"))
}
## add metadata
gb_necrosis <- AddMetaData(gb_necrosis,predictions_necrosis)
Figure 6j right panel
## plot segments
gb_necrosis <- gb_necrosis %>%
AddMetaData(read.csv(file.path("data","gb_necrosis_metadata_segmentation.csv"), row.names="barcodes"))
segmentation <- case_when(gb_necrosis$segmentation == "none" & GetTissueCoordinates(gb_necrosis)$y < -44000 & GetTissueCoordinates(gb_necrosis)$x > -322000 ~ "tumor",
gb_necrosis$segmentation == "none" & GetTissueCoordinates(gb_necrosis)$y < -47000 ~ "tumor",
gb_necrosis$segmentation == "none" & GetTissueCoordinates(gb_necrosis)$y > -44000 & GetTissueCoordinates(gb_necrosis)$x < -322000 ~ "necrosis",
gb_necrosis$segmentation == "none" ~ "tumor",
T ~ gb_necrosis$segmentation )
names(segmentation) <- colnames(gb_necrosis)
gb_necrosis$segmentation_cor <- segmentation
## celltype bar plot per segments
gb_necrosis_meta <- gb_necrosis[[]] %>%
mutate(segmentation_cor=factor(segmentation_cor,levels=c("tumor","necrosis"))) %>%
group_by(segmentation_cor,predicted.id_cor) %>%
summarise(cell_count=n()) %>%
group_by(segmentation_cor) %>%
mutate(total_cells = sum(cell_count),
cell_pct=round(cell_count/total_cells*100,2),
label=paste0("(",cell_pct,"%)"),
seg_total=paste0("\n(n=",total_cells,")"),
segmentation_cor2=paste0(segmentation_cor,"\n(n=",total_cells,")"))
gb_necrosis_meta %>%
ggplot(aes(x=segmentation_cor, y=cell_pct, fill=reorder(predicted.id_cor, cell_pct), label = label)) +
geom_col(position = "stack", width = .5,alpha=.8, color="black",lwd =.1) +
scale_y_continuous(breaks = c(0,50,100)) +
#scale_fill_tq(guide_none()) +
scale_fill_manual(values = cell_cols[unique(gb_necrosis_meta$predicted.id_cor)]) +
geom_text_repel(position = position_stack_and_nudge(vjust=.5,y=3), max.overlaps = 30) +
theme_minimal() +
theme(panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(size=15)) +
#coord_flip() +
labs(y="Cell percentage [%]",x=element_blank())

Error in head.data.frame(., coords_gb) :
invalid 'n' - must be numeric, possibly NA.
LS0tCnRpdGxlOiAiRmlndXJlLTYtY29kZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyIExvYWQgcGFja2FnZXMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoVUNlbGwpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShTZXVyYXREaXNrKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShhc3NlcnR0aGF0KQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkodGlkeXF1YW50KQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoRW5oYW5jZWRWb2xjYW5vKQpsaWJyYXJ5KE1PRkEyKQpsaWJyYXJ5KEhERjVBcnJheSkKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKbGlicmFyeShjaXJjbGl6ZSkKbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmxpYnJhcnkoU1BBVEEyKQpsaWJyYXJ5KE5JQ0hFUykKbGlicmFyeSh0aWR5cXVhbnQpCnNvdXJjZShmaWxlLnBhdGgoIlIiLCJmdW5jdGlvbnMuUiIpKQpgYGAKCiMjIyBGaWd1cmUgNmIKYGBge3IgIEZpZ3VyZSBGNmIsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbG9hZChmaWxlLnBhdGgoImRhdGEiLCJtdWx0aW1vZGFsX2hhcm1vbnlfaW50ZWdyYXRlZF9nYi5SRGF0YSIpKQoKYWxsIDwtIHJlZnF1ZXJ5X2htICNMb2FkSDVTZXVyYXQoZmlsZS5wYXRoKCJkYXRhIiwibXVsdGltb2RhbF9oYXJtb255X2ludGVncmF0ZWRfZ2IuSDVTZXVyYXQiKSkKcm0ocmVmcXVlcnlfaG0pCgojIyBjZWxsIGN5Y2xlIHNjb3JpbmcKcy5nZW5lcyA8LSBjYy5nZW5lcyRzLmdlbmVzCmcybS5nZW5lcyA8LSBjYy5nZW5lcyRnMm0uZ2VuZXMKCiMgQ3JlYXRlIG91ciBTZXVyYXQgb2JqZWN0IGFuZCBjb21wbGV0ZSB0aGUgaW5pdGFsaXphdGlvbiBzdGVwcwphbGwgPC0gQ2VsbEN5Y2xlU2NvcmluZyhhbGwsIHMuZmVhdHVyZXMgPSBzLmdlbmVzLCBnMm0uZmVhdHVyZXMgPSBnMm0uZ2VuZXMpCmNjX3Njb3JlcyA8LSBTY29yZVNpZ25hdHVyZXNfVUNlbGwoYWxsW1siUk5BIl1dQGNvdW50cywgZmVhdHVyZXM9bGlzdChzLmZlYXR1cmVzID0gcy5nZW5lcywgZzJtLmZlYXR1cmVzID0gZzJtLmdlbmVzKSkKYWxsIDwtIEFkZE1ldGFEYXRhKGFsbCwgYXMuZGF0YS5mcmFtZShjY19zY29yZXMpKQoKIyMgYWRqdXN0IGNsdXN0ZXIgb3JkZXIKb3JkZXJfY2x1c3RlcnMgPC0gZGF0YS5mcmFtZShzZXVyYXRfY2x1c3RlcnM9IGFsbCRzZXVyYXRfY2x1c3RlcnMsIHJvdy5uYW1lcyA9IHJvd25hbWVzKGFsbFtbXV0pKSAlPiUKICBiaW5kX2NvbHMoYXMuZGF0YS5mcmFtZSh0KGFsbFtbIlJOQSJdXUBzY2FsZS5kYXRhKSkpICU+JQogIGdyb3VwX2J5KHNldXJhdF9jbHVzdGVycykgJT4lCiAgc3VtbWFyaXplX2FsbCguZnVucz1tZWFuKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkKCiMjIGFkanVzdCBjbHVzdGVyIG9yZGVyCm9yZGVyX2NsdXN0ZXJzIDwtIGRhdGEuZnJhbWUoc2V1cmF0X2NsdXN0ZXJzPSBhbGwkc2V1cmF0X2NsdXN0ZXJzLCByb3cubmFtZXMgPSByb3duYW1lcyhhbGxbW11dKSkgJT4lCiAgYmluZF9jb2xzKGFzLmRhdGEuZnJhbWUodChhbGxbWyJSTkEiXV1Ac2NhbGUuZGF0YSkpKSAlPiUKICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMpICU+JQogIHN1bW1hcml6ZV9hbGwoLmZ1bnM9bWVhbikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCnJvd25hbWVzKG9yZGVyX2NsdXN0ZXJzKSA8LSBvcmRlcl9jbHVzdGVycyRzZXVyYXRfY2x1c3RlcnMKb3JkZXJfY2x1c3RlcnMgPC0gb3JkZXJfY2x1c3RlcnMkc2V1cmF0X2NsdXN0ZXJzW2hjbHVzdChkaXN0KG9yZGVyX2NsdXN0ZXJzWywtMV0pKSRvcmRlcl0KCmxldmVscyhhbGwpIDwtIHJldihvcmRlcl9jbHVzdGVycylbYygxMiwxNCwxMywxNTozMCwxMToxKV0KCiMjIGFkanVzdCBjZWxsIHR5cGVzCmNlbGx0eXBlX2NvciA8LSBjYXNlX3doZW4oCiAgYWxsJHNldXJhdF9jbHVzdGVycyAlaW4lIGMoIjE5IiwiMjkiKSB+ICJOZXVyb2VjdG9kZXJtYWwiLAogIGFsbCRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKCIxNyIpIH4gIkNBTXMiLAogIGFsbCRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKCIzIiwiNyIsIjExIiwiMTQiLCIxNiIsIjAiLCIxMiIsIjEiLCI1IikgfiAiTUciLAogIGFsbCRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKCIxNSIsIjI1IiwiNCIpICYgYWxsJGRpYWdub3NpcyA9PSAiR0IiIH4gIm1vVEFNcyIsCiAgYWxsJHNldXJhdF9jbHVzdGVycyAlaW4lIGMoIjIiKSAmIGFsbCRkaWFnbm9zaXMgPT0gIkdCIiB+ICJtZ1RBTXMiLAogIGFsbCRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKCI4IikgfiAiQ2xhc3MuIE1vbm8iLAogIGFsbCRwcmVkaWN0ZWQuY2VsbHR5cGUgPT0gIkNEMTQgTW9ubyIgfiAiQ2xhc3MuIE1vbm8iLAogIGFsbCRwcmVkaWN0ZWQuY2VsbHR5cGUgPT0gIkNEMTYgTW9ubyIgJiBhbGwkc2V1cmF0X2NsdXN0ZXJzID09ICgiMjMiKSB+ICJOb24tQ2xhc3MuIE1vbm8iLAogIFQgfiBhbGwkcHJlZGljdGVkLmNlbGx0eXBlCikKbmFtZXMoY2VsbHR5cGVfY29yKSA8LSBjb2xuYW1lcyhhbGwpCmFsbCRjZWxsdHlwZV9jb3IgPC0gY2VsbHR5cGVfY29yCgojIyBwbG90IGNsdXN0ZXJzCkRpbVBsb3QoYWxsLCBsYWJlbCA9IFQsIHB0LnNpemUgPSAxLCByZXBlbCA9IFQpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhjb2xvcnNfbWFueSwgY29sb3JzLHVubmFtZShwYWxldHRlX2dyZWVuKCkpKVstYygxNCwyMSwyOCldKSArCiAgdGhlbWVfdm9pZCgpICsKICBOb0xlZ2VuZCgpICsKICBsYWJzKHRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpgYGAKIyMjIEZpZ3VyZSA2YyAtIHRvcCBwYW5lbApgYGB7ciBGaWd1cmUgRjZjIHRvcCwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpEaW1QbG90KGFsbCwgZ3JvdXAuYnkgPSAiZGlhZ25vc2lzIiwgIGxhYmVsID0gVCkgKwogICNzY2FsZV9jb2xvcl90cSh0aGVtZSA9ICJkYXJrIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB1bm5hbWUocGFsZXR0ZV9ncmVlbigpKVtjKDUsNyldKSArIAogIHRoZW1lX3ZvaWQoKSArCiAgTm9MZWdlbmQoKSArCiAgbGFicyh0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMgRmlndXJlIDZjIC0gYm90dG9tIHBhbmVsCmBgYHtyIEZpZ3VyZSBGNmMgYm90dG9tLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmFsbFtbXV0gJT4lIAogIG11dGF0ZShzZXVyYXRfY2x1c3RlcnM9ZmFjdG9yKHNldXJhdF9jbHVzdGVycywgbGV2ZWxzPWxldmVscyhhbGwpKSkgJT4lIAogIG1vc2FpY0dHMihYPSJzZXVyYXRfY2x1c3RlcnMiLEZJTEw9ImRpYWdub3NpcyIsIGNvbG9ycyA9IHVubmFtZShwYWxldHRlX2dyZWVuKCkpW2MoNSw3KV0pCgphbGxbW11dICU+JSAKICBoeXBlcl90ZXN0X24odmFyMT0ic2V1cmF0X2NsdXN0ZXJzIix2YXIyPSJkaWFnbm9zaXMiKQpgYGAKCiMjIyBGaWd1cmUgNmQgLSB0b3AgcGFuZWwKYGBge3IgRmlndXJlIEY2ZCB0b3AsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KRGltUGxvdChhbGwsIGdyb3VwLmJ5ID0gImNvbXBhcnRtZW50IiwgbGFiZWwgPSBUKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHVubmFtZShwYWxldHRlX2RhcmsoKSlbYygyLDQpXSkgKyAKICB0aGVtZV92b2lkKCkgKwogIE5vTGVnZW5kKCkgKwogIGxhYnModGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKCiMjIyBGaWd1cmUgNmQgLSBib3R0b20gcGFuZWwKYGBge3IgRmlndXJlIEY2ZCBib3R0b20sIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KYWxsW1tdXSAlPiUgCiAgbXV0YXRlKHNldXJhdF9jbHVzdGVycz1mYWN0b3Ioc2V1cmF0X2NsdXN0ZXJzLCBsZXZlbHM9bGV2ZWxzKGFsbCkpKSAlPiUgCiAgbW9zYWljR0cyKFg9InNldXJhdF9jbHVzdGVycyIsRklMTD0iY29tcGFydG1lbnQiLCBjb2xvcnMgPSB1bm5hbWUocGFsZXR0ZV9kYXJrKCkpW2MoMiw0KV0pIAoKYWxsW1tdXSAlPiUgCiAgaHlwZXJfdGVzdF9uKHZhcjE9InNldXJhdF9jbHVzdGVycyIsdmFyMj0iZGlhZ25vc2lzIikKYGBgCgpgYGB7ciBzb3VyY2UgZGF0YSBGNmJfZCwgZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiMjIyBleHBvcnQgc291cmNlIGRhdGEgZmlndXJlIDRiCndyaXRlLmNzdihkYXRhLmZyYW1lKCJVTUFQXzEiPWFsbEByZWR1Y3Rpb25zJHVtYXBAY2VsbC5lbWJlZGRpbmdzWywxXSwKICAgICAgICAgICAgICAgICAgICAgIlVNQVBfMiI9YWxsQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3NbLDJdLAogICAgICAgICAgICAgICAgICAgICAiQ2x1c3RlciI9YWxsJHNldXJhdF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgIkRpYWdub3NpcyI9YWxsJGRpYWdub3NpcywKICAgICAgICAgICAgICAgICAgICAgIkNvbXBhcnRtZW50Ij1hbGwkY29tcGFydG1lbnQgLAogICAgICAgICAgICAgICAgICAgICAiQ2VsbHR5cGUiPWFsbCRjZWxsdHlwZV9jb3IpLAogICAgICAgICAgZmlsZS5wYXRoKCJkYXRhIiwic291cmNlX2RhdGEiLCJwYW5lbF9GNmJfZC5jc3YiKSkKYGBgCgojIyMgRmlndXJlIDZlCmBgYHtyIEZpZ3VyZSBGNmUsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KIyMgc3Vic2V0IGZvciB0aXNzdWUgcmVzaWRlbnQgbXllbG9pZCBjZWxscwpnYl9tZiA8LSBzdWJzZXQoYWxsLCBzdWJzZXQ9Y2VsbHR5cGVfY29yICVpbiUgYygiTUciLCJDQU1zIiwiVEFNcyIsIlRyYW5zLiBtb1RBTXMiKSAmIGRpYWdub3NpcyA9PSAiR0IiKSAjLCJNRyIKCmNvbXBfY2VsbHR5cGUgPC0gY2FzZV93aGVuKGdyZXBsKCJNRyIsZ2JfbWYkY2VsbHR5cGVfY29yKSB+ICJNRyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVCB+IHBhc3RlKGdiX21mJGNlbGx0eXBlX2NvcixnYl9tZiRjb21wYXJ0bWVudCxzZXA9Il8iKSkKCm5hbWVzKGNvbXBfY2VsbHR5cGUpIDwtIGNvbG5hbWVzKGdiX21mKQpnYl9tZiRjb21wX2NlbGx0eXBlIDwtIGNvbXBfY2VsbHR5cGUKSWRlbnRzKGdiX21mKSA8LSBnYl9tZiRjb21wX2NlbGx0eXBlCgojIyBjcmVhdGUgdGhlIG1vZmEgb2JqZWN0CmlmICghZmlsZS5leGlzdHMoZmlsZS5wYXRoKCJkYXRhIiwibW9mYV9tb2RlbF9nYl9teWVsb2lkX2NlbGxzLmg1IikpKSB7CiAgIyMgY3JlYXRlIE1PRkEgb2JqZWN0CiAgI0RlZmF1bHRBc3NheShnYl9tZikgPC0gIlJOQSIKICBnYl9tZiA8LSBnYl9tZiAlPiUgTm9ybWFsaXplRGF0YSgpICU+JSBGaW5kVmFyaWFibGVGZWF0dXJlcyhuZmVhdHVyZXMgPSA1MDAwKSAlPiUgU2NhbGVEYXRhKCkgCiAgCiAgTU9GQW9iamVjdF9hbGwgPC0gY3JlYXRlX21vZmEoZ2JfbWYsIGdyb3VwcyA9ICJjb21wX2NlbGx0eXBlIiwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGdiX21mKSwgYXNzYXk9IlJOQSIsIGV4dHJhY3RfbWV0YWRhdGEgPSBUKQogIAogICMjIHBsb3QgZGF0YSBvdmVydmlldwogIHBsb3RfZGF0YV9vdmVydmlldyhNT0ZBb2JqZWN0X2FsbCkKICAKICAjIyBEZWZhdWx0IGRhdGEgb3B0aW9ucwogIGRhdGFfb3B0cyA8LSBnZXRfZGVmYXVsdF9kYXRhX29wdGlvbnMoTU9GQW9iamVjdF9hbGwpCiAgCiAgIyMgRGVmYXVsdCBtb2RlbCBvcHRpb25zCiAgbW9kZWxfb3B0cyA8LSBnZXRfZGVmYXVsdF9tb2RlbF9vcHRpb25zKE1PRkFvYmplY3RfYWxsKQogIAogICMjIFRyYWluaW5nIG9wdGlvbnMKICB0cmFpbl9vcHRzIDwtIGdldF9kZWZhdWx0X3RyYWluaW5nX29wdGlvbnMoTU9GQW9iamVjdF9hbGwpCiAgdHJhaW5fb3B0cyRjb252ZXJnZW5jZV9tb2RlIDwtICJmYXN0IgogIHRyYWluX29wdHMkc2VlZCA8LSA0MgogIG1vZGVsX29wdHMkbnVtX2ZhY3RvcnMgPC0gMTAKICAKICAjcHJlcGFyZSBtb2ZhIG9iamVjdAogIE1PRkFvYmplY3RfYWxsIDwtIHByZXBhcmVfbW9mYSgKICAgIG9iamVjdCA9IE1PRkFvYmplY3RfYWxsLAogICAgZGF0YV9vcHRpb25zID0gZGF0YV9vcHRzLAogICAgbW9kZWxfb3B0aW9ucyA9IG1vZGVsX29wdHMsCiAgICB0cmFpbmluZ19vcHRpb25zID0gdHJhaW5fb3B0cwogICkKICAKICAjIyBnZW5lcmF0ZSBhIGhkZjUgZmlsZSBmb3IgdGhlIG91dHB1dAogIHJoZGY1OjpoNWNyZWF0ZUZpbGUoZmlsZS5wYXRoKCJkYXRhIiwibW9mYV9tb2RlbF9nYl9teWVsb2lkX2NlbGxzLmg1IikpCiAgCiAgIyMgdHJhaW4gbW9kZWwKICBNT0ZBb2JqZWN0X2FsbCA8LSBydW5fbW9mYShNT0ZBb2JqZWN0X2FsbCwgb3V0ZmlsZSA9IGZpbGUucGF0aCgiZGF0YSIsIm1vZmFfbW9kZWxfZ2JfbXllbG9pZF9jZWxscy5oNSIpLCB1c2VfYmFzaWxpc2sgPSBUKQp9IGVsc2UgewogIE1PRkFvYmplY3RfYWxsIDwtIGxvYWRfbW9kZWwoZmlsZS5wYXRoKCJkYXRhIiwibW9mYV9tb2RlbF9nYl9teWVsb2lkX2NlbGxzLmg1IikpCn0KCiMjIHBsb3QgbW9kZWwKCnBsdCA8LSBwbG90X3ZhcmlhbmNlX2V4cGxhaW5lZChNT0ZBb2JqZWN0X2FsbCwgeD0idmlldyIsIHk9ImZhY3RvciIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvdW5kKHZhbHVlLDIpKSkgKwogIGNvb3JkX2ZpeGVkKCkKCnBsdAoKYGBgCgpgYGB7ciBzb3VyY2UgZGF0YSBGNmUsIGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojIyMgZXhwb3J0IHNvdXJjZSBkYXRhIGZpZ3VyZSA0Ygp3cml0ZS5jc3YoZGF0YS5mcmFtZShwbHQkZGF0YSksCiAgICAgICAgICBmaWxlLnBhdGgoImRhdGEiLCJzb3VyY2VfZGF0YSIsInBhbmVsX0Y2ZS5jc3YiKSkKYGBgCgpgYGB7ciBGaWd1cmUgRjZmLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiMjIGdzZWEgY2x1c3RlciBwcm9maWxlcgppZiAoIWZpbGUuZXhpc3RzKGZpbGUucGF0aCgiZGF0YSIsIm1vZmFfd2VpZ2h0czJfPi4xX2diX21mLmNzdiIpKSkgewogICMjIGdzZWEgY2x1c3RlciBwcm9maWxlcgogIG1vZmFfd2VpZ2h0czIgPC0gZ2V0X3dlaWdodHMoTU9GQW9iamVjdF9hbGwsIHZpZXdzID0gIlJOQSIsIGZhY3RvcnMgPSAxOjgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSA9IFRSVUUpICU+JSAKICAgIGdyb3VwX2J5KGZhY3RvcikgJT4lIAogICAgdG9wX24oMTAwLCB3dD12YWx1ZSkKICAjZmlsdGVyKHZhbHVlPi4xKQogIAogICMjIGNvbnZlcnQgZ2VuZSBuYW1lcwogIGdlbmVzIDwtIGJpdHIodW5pcXVlKG1vZmFfd2VpZ2h0czIkZmVhdHVyZSksIGZyb21UeXBlID0gIlNZTUJPTCIsIHRvVHlwZSA9ICJFTlRSRVpJRCIsIE9yZ0RiID0gJ29yZy5Icy5lZy5kYicpCiAgY29sbmFtZXMoZ2VuZXMpWzFdIDwtICJmZWF0dXJlIgogIAogICMjIGNvbXBhcmlzb24gYmV0d2VlbiBjbHVzdGVycwogIG1vZmFfd2VpZ2h0czIgPC0gbW9mYV93ZWlnaHRzMiAlPiUgCiAgICBsZWZ0X2pvaW4oZ2VuZXNbIWR1cGxpY2F0ZWQoZ2VuZXMkZmVhdHVyZSksXSkgJT4lIAogICAgbmEub21pdCgpCiAgCiAgIyMgZXhwb3J0IG1vZmFfd2VpZ2h0MgogIHdyaXRlLmNzdihtb2ZhX3dlaWdodHMyLCBmaWxlLnBhdGgoImRhdGEiLCJtb2ZhX3dlaWdodHMyXz4uMV9nYl9tZi5jc3YiKSkKfSBlbHNlIHsKICBtb2ZhX3dlaWdodHMyIDwtIHJlYWQuY3N2KGZpbGUucGF0aCgiZGF0YSIsIm1vZmFfd2VpZ2h0czJfPi4xX2diX21mLmNzdiIpLCByb3cubmFtZXMgPSAxKQp9IAoKIyMjIG5vdGUgdGhhdCB3aXRoIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgY2x1c3RlclByb2ZpbGVyIHRoZSBwbG90IHdpbGwgbG9vayBzbGlnaHRseSBkaWZmZXJlbnQKZGlmZl9nb19icCA8LSBjb21wYXJlQ2x1c3RlcihFTlRSRVpJRCB+IGZhY3RvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPW1vZmFfd2VpZ2h0czIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1biA9IGVucmljaEdPLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9yZ0RiID0gJ29yZy5Icy5lZy5kYicsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb250ID0gIkJQIikKCnBsdCA8LSBjbHVzdGVyUHJvZmlsZXI6OmRvdHBsb3QoZGlmZl9nb19icCkKCnBsdApgYGAKCmBgYHtyIHNvdXJjZSBkYXRhIEY2ZiwgZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CiMjIyBleHBvcnQgc291cmNlIGRhdGEgZmlndXJlIDRiCndyaXRlLmNzdihtb2ZhX3dlaWdodHMyLAogICAgICAgICAgZmlsZS5wYXRoKCJkYXRhIiwic291cmNlX2RhdGEiLCJwYW5lbF9GNmYuY3N2IikpCmBgYAoKIyMjIFByZXByb2Nlc3MgdGhlIGRhdGEgZm9yIEZpZ3VyZSA2ZyAtIGdldCB0aGUgcmVmZXJlbmNlIGRhdGEKYGBge3IgRmlndXJlIDZnIHByZXByb2Nlc3MsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KCmlmICghZmlsZS5leGlzdHMoZmlsZS5wYXRoKCJkYXRhIiwiR0JNMV9sZWZ0LlJEYXRhIikpKSB7IyMgb2JqZWN0IDggY29udGFpbnMgbGVwdG9tZW5pbmdlcyBhbmQgY29ydGV4CiAgIyMgc3Vic2V0IGl0IGFuZCBjcmVhdGUgc3BhdGlhbCBzZWdtZW50cwogIGNvb3JkX2RmIDwtIHJlYWQuY3N2KGZpbGUucGF0aCgiZGF0YSIsIk91dF9HQk0xX1NjYWxlNTBfSGlnaF9Qcmlvcl9zNTBfc2Q1MF9jb25mMDgiLCJiMWhpX2N0cmxfY29vcmRfcHJpb3IwOC5jc3YiKSkKICBjb2xuYW1lcyhjb29yZF9kZikgPC0gYygiYmFyY29kZXMiLCJ4IiwieSIpCiAgY291bnRfbXRyICA8LSByZWFkLmNzdihmaWxlLnBhdGgoImRhdGEiLCJPdXRfR0JNMV9TY2FsZTUwX0hpZ2hfUHJpb3JfczUwX3NkNTBfY29uZjA4Iiwic2VnbWVudGF0aW9uX2NvdW50c19maWx0X3ByaW9yMDguY3N2Iikscm93Lm5hbWVzID0gMSkKICBjb3VudF9tdHIgPC0gY291bnRfbXRyWywgY29sU3Vtcyhjb3VudF9tdHIpID49IDVdCiAgCiAgIyMgc3Vic2V0IGNvb3JkX2RmIGZvciB0aGUgbGVmdCBoYWxmCiAgY29vcmRzX0dCTTFfbGVmdCA8LSBjb29yZF9kZltjb29yZF9kZiR4IDwgMTIwOTUsXQogIGNvdW50X210cl9HQk0xX2xlZnQgPC0gTWF0cml4KGFzLm1hdHJpeChjb3VudF9tdHJbLGNvbG5hbWVzKGNvdW50X210cikgJWluJSBjb29yZHNfR0JNMV9sZWZ0JGJhcmNvZGVzXSksIHNwYXJzZSA9IFQpICAgICAgIAogIGJhcmNvZGVzX0dCTTFfbGVmdCA8LSBjb2xuYW1lcyhjb3VudF9tdHJfR0JNMV9sZWZ0KVtjb2xuYW1lcyhjb3VudF9tdHJfR0JNMV9sZWZ0KSAlaW4lIGNvb3Jkc19HQk0xX2xlZnQkYmFyY29kZXNdCiAgY29vcmRzX0dCTTFfbGVmdCA8LSBjb29yZHNfR0JNMV9sZWZ0W2Nvb3Jkc19HQk0xX2xlZnQkYmFyY29kZXMgJWluJSBiYXJjb2Rlc19HQk0xX2xlZnQsXQogIAogIEdCTTFfbGVmdCA8LSBpbml0aWF0ZVNwYXRhT2JqZWN0X0NvdW50TXRyKAogICAgY29vcmRzX2RmID0gY29vcmRzX0dCTTFfbGVmdCwgIyB5b3VyIGNvb3JkaW5hdGUgZGF0YS5mcmFtZQogICAgY291bnRfbXRyID0gY291bnRfbXRyX0dCTTFfbGVmdCwgIyBhIG1hdHJpeCB3aXRoIHVucHJvY2Vzc2VkIGNvdW50IHZhbHVlcwogICAgc2FtcGxlX25hbWUgPSAiQ3RybEN0eDRfR0JNMV9sZWZ0IiwKICAgIGltYWdlID0gZmlsZS5wYXRoKCJkYXRhIiwiT3V0X0dCTTFfU2NhbGU1MF9IaWdoX1ByaW9yX3M1MF9zZDUwX2NvbmYwOCIsIiIpCiAgKQogIEdCTTFfbGVmdCA8LSBjcmVhdGVUcmFqZWN0b3JpZXMob2JqZWN0ID0gR0JNMV9sZWZ0ICkKICBHQk0xX2xlZnQgPC0gY3JlYXRlU2VnbWVudGF0aW9uKG9iamVjdCA9IEdCTTFfbGVmdCApCiAgCiAgc2F2ZShHQk0xX2xlZnQsIGZpbGUgPSBmaWxlLnBhdGgoImRhdGEiLCJHQk0xX2xlZnQuUkRhdGEiKSkKICAKICAjIyBzdWJzZXQgY29vcmRfZGYgZm9yIHRoZSByaWdodCBoYWxmCiAgY29vcmRzX0dCTTFfcmlnaHQgPC0gY29vcmRfZGZbY29vcmRfZGYkeCA+IDEyMDk1LF0KICBjb3VudF9tdHJfR0JNMV9yaWdodCA8LSBNYXRyaXgoYXMubWF0cml4KGNvdW50X210clssY29sbmFtZXMoY291bnRfbXRyKSAlaW4lIGNvb3Jkc19HQk0xX3JpZ2h0JGJhcmNvZGVzXSksIHNwYXJzZSA9IFQpICAgICAgIAogIGJhcmNvZGVzX0dCTTFfcmlnaHQgPC0gY29sbmFtZXMoY291bnRfbXRyX0dCTTFfcmlnaHQpW2NvbG5hbWVzKGNvdW50X210cl9HQk0xX3JpZ2h0KSAlaW4lIGNvb3Jkc19HQk0xX3JpZ2h0JGJhcmNvZGVzXQogIGNvb3Jkc19HQk0xX3JpZ2h0IDwtIGNvb3Jkc19HQk0xX3JpZ2h0W2Nvb3Jkc19HQk0xX3JpZ2h0JGJhcmNvZGVzICVpbiUgYmFyY29kZXNfR0JNMV9yaWdodCxdCiAgCiAgR0JNMV9yaWdodCA8LSBpbml0aWF0ZVNwYXRhT2JqZWN0X0NvdW50TXRyKAogICAgY29vcmRzX2RmID0gY29vcmRzX0dCTTFfcmlnaHQsICMgeW91ciBjb29yZGluYXRlIGRhdGEuZnJhbWUKICAgIGNvdW50X210ciA9IGNvdW50X210cl9HQk0xX3JpZ2h0LCAjIGEgbWF0cml4IHdpdGggdW5wcm9jZXNzZWQgY291bnQgdmFsdWVzCiAgICBzYW1wbGVfbmFtZSA9ICJDdHJsQ3R4NF9HQk0xX3JpZ2h0IiwKICAgIGltYWdlID0gIi9Vc2Vycy9yb21hbnNhbmtvd3NraS9Eb2N1bWVudHMvc2luZ2xlX2NlbGxfYW5hbHlzaXMvQ2FydGFuYV9zcGF0aWFsXzIwMjIvZGF0YS9EQVBJXzUwJV9zY2FsZWQvREFQSV9DdHJsIEN0eCA0X0lTQVAxMzU4NjMwMV8yMDIyMDYyOS5wbmciCiAgKQogICNHQk0xX3JpZ2h0IDwtIGNyZWF0ZVRyYWplY3RvcmllcyhvYmplY3QgPSBHQk0xX3JpZ2h0ICkKICBHQk0xX3JpZ2h0IDwtIGNyZWF0ZVNlZ21lbnRhdGlvbihvYmplY3QgPSBHQk0xX3JpZ2h0ICkKICBHQk0xX3JpZ2h0IDwtIGNyZWF0ZVRyYWplY3RvcmllcyhvYmplY3QgPSBHQk0xX3JpZ2h0ICkKICBzYXZlKEdCTTFfcmlnaHQsIGZpbGUgPSBmaWxlLnBhdGgoImRhdGEiLCJHQk0xX3JpZ2h0LlJEYXRhIikpCiAgCn0gZWxzZSB7CiAgbG9hZChmaWxlLnBhdGgoImRhdGEiLCJHQk0xX2xlZnQuUkRhdGEiKSkKICBsb2FkKGZpbGUucGF0aCgiZGF0YSIsIkdCTTFfcmlnaHQuUkRhdGEiKSkKICAKfQoKIyMgc2V0dXAgc2V1cmF0IG9iamVjdAppZiAoIWZpbGUuZXhpc3RzKGZpbGUucGF0aCgiZGF0YSIsInNldXJhdF9nYm0xX2xlZnQuSDVTZXVyYXQiKSkpIHsKICBHQk0xX2xlZnRfc2V1cmF0IDwtIEdCTTFfbGVmdCAlPiUgCiAgICB0cmFuc2Zvcm1TcGF0YVRvU2V1cmF0CiAgCiAgR0JNMV9yaWdodF9zZXVyYXQgPC0gR0JNMV9yaWdodCAlPiUgCiAgICB0cmFuc2Zvcm1TcGF0YVRvU2V1cmF0CiAgCiAgU2F2ZUg1U2V1cmF0KEdCTTFfbGVmdF9zZXVyYXQsIGZpbGUucGF0aCgiZGF0YSIsInNldXJhdF9nYm0xX2xlZnQuSDVTZXVyYXQiKSkKICBTYXZlSDVTZXVyYXQoR0JNMV9yaWdodF9zZXVyYXQsIGZpbGUucGF0aCgiZGF0YSIsInNldXJhdF9nYm0xX3JpZ2h0Lkg1U2V1cmF0IikpCn0gZWxzZSB7CiAgR0JNMV9sZWZ0X3NldXJhdCA8LSAgTG9hZEg1U2V1cmF0KGZpbGUucGF0aCgiZGF0YSIsInNldXJhdF9nYm0xX2xlZnQuSDVTZXVyYXQiKSkKICBHQk0xX3JpZ2h0X3NldXJhdCA8LSBMb2FkSDVTZXVyYXQoZmlsZS5wYXRoKCJkYXRhIiwic2V1cmF0X2dibTFfcmlnaHQuSDVTZXVyYXQiKSkKfQoKIyMgYXNzaWduIGNlbGwgdHlwZXMKIyMgcGxvdCBjZWxsdHlwZXMKCiMjIG1lcmdlIGJvdGggb2JqZWN0cwphbGwgPC0gbWVyZ2UoeD1HQk0xX2xlZnRfc2V1cmF0LCBHQk0xX3JpZ2h0X3NldXJhdCkKClZhcmlhYmxlRmVhdHVyZXMoYWxsKSA8LSByb3duYW1lcyhhbGwpIAphbGwgPC0gYWxsICU+JSAKICBOb3JtYWxpemVEYXRhKCkgJT4lIAogIFNjYWxlRGF0YSgpICU+JSAKICBSdW5QQ0EoKQoKIyMgbG9hZCByZWZlcmVuY2UKcmVmZXJlbmNlIDwtIExvYWRINVNldXJhdChmaWxlLnBhdGgoImRhdGEiLCJyZWZlcmVuY2Vfc2V1cmF0X2diLkg1U2V1cmF0IikpCiAgCiMjIGRvd25zYW1wbGUgcmVmZXJlbmNlCnNldC5zZWVkKDc5MTA2KQpjZWxsX2lkcyA8LSByZWZlcmVuY2VbW11dICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNlbGxJRCIpICU+JSAKICBncm91cF9ieShjZWxsdHlwZV9jb3IpICU+JSAKICBzbGljZV9zYW1wbGUobj0yMDAsIHJlcGxhY2UgPSBUKSAlPiUgCiAgZGlzdGluY3QoY2VsbElELCBjZWxsdHlwZV9jb3IpCgojIyBzdWJzZXQgZm9yIGdlbmVzIHByZXNlbnQgaW4gdGhlIG5hbm9zdHJpbmcgZGF0YXNldApyZWZlcmVuY2UgPC0gcmVmZXJlbmNlW3Jvd25hbWVzKGFsbCksY2VsbF9pZHMkY2VsbElEXQoKIyMgcmVtb3ZlIGNlbGxzIHdpdGggZmV3IGNvdW50cwpyZWZlcmVuY2UgPC0gcmVmZXJlbmNlWyxjb2xTdW1zKHJlZmVyZW5jZVtbIlJOQSJdXUBjb3VudHMpPjEwXQoKIyMgTm9ybWFsaXplIGRhdGEKVmFyaWFibGVGZWF0dXJlcyhyZWZlcmVuY2UpIDwtIHJvd25hbWVzKHJlZmVyZW5jZSkKRGVmYXVsdEFzc2F5KHJlZmVyZW5jZSkgPC0gIlJOQSIKcmVmZXJlbmNlIDwtIHJlZmVyZW5jZSAlPiUgCiAgTm9ybWFsaXplRGF0YSgpICU+JSAKICBTY2FsZURhdGEoKSAlPiUgCiAgUnVuUENBKCkKCiMjIGNsYXNzaWZ5IG12cCBjZWxscwppZiAoIWZpbGUuZXhpc3RzKGZpbGUucGF0aCgiZGF0YSIsIkdCMV9jZWxsdHlwZV9wcmVkaWN0aW9ucy5SRGF0YSIpKSkgewogICMjIG1hcCBjZWxsdHlwZXMKICBhbmNob3JzX0dCMSA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHJlZmVyZW5jZSAsIHF1ZXJ5ID0gYWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6MzAsIHJlZmVyZW5jZS5yZWR1Y3Rpb24gPSAicGNhIikKICBwcmVkaWN0aW9uc19HQjEgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnNfR0IxLCByZWZkYXRhID0gcmVmZXJlbmNlJGNlbGx0eXBlX2NvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOjMwLCBrLndlaWdodCA9IDIwKQogIAogICMjIGFkanVzdCBjZWxsIGxhYmVscwogIHByZWRpY3Rpb25zX0dCMSRwcmVkaWN0ZWQuaWRfY29yIDwtIGNhc2Vfd2hlbihwcmVkaWN0aW9uc19HQjEkcHJlZGljdGVkLmlkID09ICJUcmFuc2l0b3J5IE1vLVRBTSIgfiAiVHIuIG1vVEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIk1vLVRBTSIsIHByZWRpY3Rpb25zX0dCMSRwcmVkaWN0ZWQuaWQpIH4gIm1vVEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIlRBTSIsIHByZWRpY3Rpb25zX0dCMSRwcmVkaWN0ZWQuaWQpIH4gIm1nVEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVCB+IHByZWRpY3Rpb25zX0dCMSRwcmVkaWN0ZWQuaWQpCiAgCiAgc2F2ZShwcmVkaWN0aW9uc19HQjEsIGZpbGUgPSBmaWxlLnBhdGgoImRhdGEiLCJHQjFfY2VsbHR5cGVfcHJlZGljdGlvbnMuUkRhdGEiKSkKfSBlbHNlIHsKICBsb2FkKGZpbGUucGF0aCgiZGF0YSIsIkdCMV9jZWxsdHlwZV9wcmVkaWN0aW9ucy5SRGF0YSIpKQp9CgoKCmBgYAoKIyMjIFBsb3QgZmlndXJlIDZnIC0gdG9wIHBhbmVsCmBgYHtyIEZpZ3VyZSA2ZyB0b3AgcGFuZWwsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KIyMgYWRkIG1ldGFkYXRhIAphbGwgPC0gQWRkTWV0YURhdGEoYWxsLHByZWRpY3Rpb25zX0dCMSkKCiMjICMjIHBsb3QKY29vcmQgPC0gcmJpbmQoR0JNMV9sZWZ0QGNvb3JkaW5hdGVzW1sxXV0sCiAgICAgICAgICAgICAgIEdCTTFfcmlnaHRAY29vcmRpbmF0ZXNbWzFdXSkKcm93bmFtZXMoY29vcmQpIDwtIGNvb3JkJGJhcmNvZGVzCgojIyByZW9yZGVyIGJhc2VkIG9uIHRoZSBzZXVyYXQgb2JqZWN0CmNvb3JkIDwtIGNvb3JkW2NvbG5hbWVzKGFsbCksXQoKI3Jvd25hbWVzKGNvb3JkKSA8LSBnc3ViKCJjZWxsIiwiWCIsY29vcmQkYmFyY29kZXMpCgpjb29yZCRzZWdtZW50YXRpb24gPC0gZ3N1YigiWzEtOV0kIiwiIixhbGxbW11dW3Jvd25hbWVzKGNvb3JkKSxdJHNlZ21lbnRhdGlvbikKY29vcmQkc2VnbWVudGF0aW9uX2RldGFpbCA8LSBhbGxbW11dW3Jvd25hbWVzKGNvb3JkKSxdJHNlZ21lbnRhdGlvbgpjb29yZCRjZWxsdHlwZV9jb3IgPC0gYWxsW1tdXVtyb3duYW1lcyhjb29yZCksXSRwcmVkaWN0ZWQuaWRfY29yCgojIyBkZWZpbmUgY29sb3JzCmNlbGxfY29scyA8LSB1bm5hbWUocGFsZXR0ZV9saWdodCgpKQpuYW1lcyhjZWxsX2NvbHMpIDwtIGMoIkFzdHJvIiwiQ0FNcyIsIkVuZG90aGVsaWFsIGNlbGxzIiwiRmlicm9ibGFzdCIsIkx5bXBob2N5dGVzIiwibWdUQU1zIiwiTXVyYWwgY2VsbHMiLCJOZXVyb24iLCJPbGlnbyIsIlR1bW9yIiwibW9UQU1zIiwiVHIuIG1vVEFNcyIpCgpjb29yZCAlPiUgCiAgZ2dwbG90KGFlcyh4LHksY29sb3I9Y2VsbHR5cGVfY29yKSkgKwogIGdlb21fcG9pbnQocGNoPTIwLCBzaXplPS4wMDEpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2VsbF9jb2xzW3VuaXF1ZShjb29yZCRjZWxsdHlwZV9jb3IpXSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgY29vcmRfZml4ZWQoKSAKCmBgYAoKIyMjIFBsb3QgRmlndXJlIDZnIC0gYm90dG9tIHBhbmVsCmBgYHtyIEZpZ3VyZSA2ZyBsZWZ0IHBhbmVsLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmNvb3JkIDwtIGNvb3JkICU+JSAKICBtdXRhdGUoc2VnbWVudGF0aW9uX2RldGFpbD0gaWZlbHNlKHNlZ21lbnRhdGlvbl9kZXRhaWw9PSJub25lIiwgIlNvbGlkIFR1bW9yIiwgc2VnbWVudGF0aW9uX2RldGFpbCkpIApjb29yZCAlPiUgCiAgZ2dwbG90KGFlcyh4LHksY29sb3I9c2VnbWVudGF0aW9uX2RldGFpbCkpICsKICBnZW9tX3BvaW50KHBjaD0yMCwgc2l6ZT0uMDAxKSArCiAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjZWxsX2NvbHNbdW5pcXVlKGNvb3JkJGNlbGx0eXBlX2NvcildKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDMiKSArCiAgdGhlbWVfdm9pZCgpICsKICBjb29yZF9maXhlZCgpIAoKYGBgCgoKIyMjIEZpZ3VyZSA2aCAtIGxlZnQgcGFuZWwKYGBge3IgRmlndXJlIDZoIGxlZnQgcGFuZWwsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KY29vcmQgJT4lIAogIGZpbHRlcihzZWdtZW50YXRpb25fZGV0YWlsPT0iaHlwb3hpYTkiKSAlPiUgCiAgZ2dwbG90KGFlcyh4LHksY29sb3I9Y2VsbHR5cGVfY29yKSkgKwogIGdlb21fcG9pbnQocGNoPTIwLCBzaXplPTIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2VsbF9jb2xzW3VuaXF1ZShjb29yZCRjZWxsdHlwZV9jb3IpXSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgY29vcmRfZml4ZWQoKSArCiAgTm9MZWdlbmQoKSArCiAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gbWF4KHgpLTU1MCwgeSA9IG1pbih5KSs1MCwgeGVuZCA9IG1heCh4KS01MCwgeWVuZCA9IG1pbih5KSs1MCksIHNpemU9MSwgY29sb3I9ImJsYWNrIikgKwogIGdlb21fdGV4dChhZXMobWF4KHgpLTMxMCwgeSA9IG1pbih5KSsxMzAsbGFiZWw9IjUwMCBweCIpKQoKYGBgCgpgYGB7ciBzb3VyY2UgZGF0YSBGNmdfaSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQp3cml0ZS5jc3YoY29vcmQsIGZpbGUucGF0aCgiZGF0YSIsInNvdXJjZV9kYXRhIiwicGFuZWxfRjZnX2kuY3N2IikpCmBgYAoKCiMjIyBGaWd1cmUgNmggLSBtaWRkbGUgcGFuZWwKYGBge3IgRmlndXJlIDZoIG1pZGRsZSBwYW5lbCwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQoKIyMgYXNzZXNzIGdlbmVzIGFsb25nIHRoZSB0cmFqZWN0b3J5CmFsbF9nZW5lcyA8LSBnZXRHZW5lcyhHQk0xX3JpZ2h0KQphdGRmX2dlbmVzIDwtIGFzc2Vzc1RyYWplY3RvcnlUcmVuZHMob2JqZWN0ID0gR0JNMV9yaWdodCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFqZWN0b3J5X25hbWUgPSAiaHlwb3hpYV9sZWZ0X3Nob3J0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXMgPSBhbGxfZ2VuZXMpCgojIG91dHB1dCBleGFtcGxlCmF0ZGZfZ2VuZXMKCiMjIGFzY2VuZGluZyBnZW5lcwphc2NlbmRpbmdfZ2VuZXMgPC0KICBmaWx0ZXJUcmFqZWN0b3J5VHJlbmRzKGF0ZGYgPSBhdGRmX2dlbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgbGltaXQgPSA2OCwKICAgICAgICAgICAgICAgICAgICAgICAgIHRyZW5kcyA9ICJHcmFkaWVudCBhc2NlbmRpbmciLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlc19vbmx5ID0gRkFMU0UpICU+JSAjIHJldHVybiBhIGRhdGEuZnJhbWUKICB0b3BfbigtMTAsIHd0PWF1YykKCmFzY2VuZGluZ19nZW5lcwoKZGVzY2VuZGluZ19nZW5lcyA8LQogIGZpbHRlclRyYWplY3RvcnlUcmVuZHMoYXRkZiA9IGF0ZGZfZ2VuZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdCA9IDY4LAogICAgICAgICAgICAgICAgICAgICAgICAgdHJlbmRzID0gYygiR3JhZGllbnQgYXNjZW5kaW5nIiwgIkdyYWRpZW50IGRlc2NlbmRpbmciKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXNfb25seSA9IEZBTFNFKSAlPiUgIyByZXR1cm4gYSBkYXRhLmZyYW1lCiAgdG9wX24oLTEwLCB3dD1hdWMpCgpkZXNjZW5kaW5nX2dlbmVzCmRlc2NlbmRpbmdfZ2VuZXNfdmVjIDwtIGRlc2NlbmRpbmdfZ2VuZXMkdmFyaWFibGVzCgojIyBwbG90IGhlYXRtYXAKaG1fY29sb3JzIDwtIHZpcmlkaXM6OmluZmVybm8obiA9IDEwMCkKCnBsb3RUcmFqZWN0b3J5SGVhdG1hcChvYmplY3QgPSBHQk0xX3JpZ2h0LCAKICAgICAgICAgICAgICAgICAgICAgIHRyYWplY3RvcnlfbmFtZSA9ICJoeXBveGlhX2xlZnRfc2hvcnQiLAogICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGVzID0gZGVzY2VuZGluZ19nZW5lc192ZWMsCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlX3Jvd3MgPSAibWF4aW1hIiwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9ycyA9IGhtX2NvbG9ycywKICAgICAgICAgICAgICAgICAgICAgIHNob3dfcm93bmFtZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgc3BsaXRfY29sdW1ucyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIHNtb290aF9zcGFuID0gMC41KQoKYGBgCgojIyMgRmlndXJlIDZpCmBgYHtyIEZpZ3VyZSA2aSwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojIyBwbG90IGNvbXBvc2l0aW9uIG9mIGh5cG94aWEgOQpjb29yZDMgPC0gY29vcmQgJT4lIAogIGdyb3VwX2J5KHNlZ21lbnRhdGlvbl9kZXRhaWwsIGNlbGx0eXBlX2NvcikgJT4lIAogIHN1bW1hcmlzZShjZWxsX2NvdW50PW4oKSkgJT4lIAogIGdyb3VwX2J5KHNlZ21lbnRhdGlvbl9kZXRhaWwsIC5kcm9wID0gRikgJT4lIAogIG11dGF0ZSh0b3RhbF9jZWxscyA9IHN1bShjZWxsX2NvdW50KSwKICAgICAgICAgY2VsbF9wY3Q9cm91bmQoY2VsbF9jb3VudC90b3RhbF9jZWxscyoxMDAsMiksCiAgICAgICAgIGxhYmVsPXBhc3RlMChjZWxsdHlwZV9jb3IsIiAoIixjZWxsX3BjdCwiJSkiKSwKICAgICAgICAgQ2VsbF9vcmRlcmVkPXJlb3JkZXIoY2VsbHR5cGVfY29yLCBjZWxsX3BjdCksCiAgICAgICAgIHNlZ190b3RhbD1wYXN0ZTAoc2VnbWVudGF0aW9uX2RldGFpbCwgIlxuKG49Iix0b3RhbF9jZWxscywiKSIpKSAKCgpjb29yZDMgJT4lIAogIGZpbHRlcihzZWdtZW50YXRpb25fZGV0YWlsICVpbiUgYygibm9uZSIsICJoeXBveGlhOSIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXNlZ190b3RhbCwgeT1jZWxsX3BjdCwgZmlsbD1DZWxsX29yZGVyZWQsIGxhYmVsID0gbGFiZWwpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAic3RhY2siLCB3aWR0aCA9IC41LGFscGhhPS44LCBjb2xvcj0iYmxhY2siLGx3ZCA9LjEpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLDUwLDEwMCkpICsKICAjc2NhbGVfZmlsbF90cShndWlkZV9ub25lKCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjZWxsX2NvbHNbdW5pcXVlKGNvb3JkJGNlbGx0eXBlX2NvcildKSArCiAgZ2VvbV90ZXh0X3JlcGVsKHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2tfYW5kX251ZGdlKHZqdXN0PS41LHk9MyksIG1heC5vdmVybGFwcyA9IDMwKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHk9IkNlbGwgcGVyY2VudGFnZSBbJV0iLHg9ZWxlbWVudF9ibGFuaygpKQoKYGBgCiMjIyBwcmVwcm9jZXNzIGRhdGEgZm9yIEZpZ3VyZSA2agpgYGB7ciBGaWd1cmUgNmogcHJlcHJvY2Vzcywgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpsb2FkKGZpbGUucGF0aCgiZGF0YSIsImdiX25lY3Jvc2lzLlJEYXRhIikpCgpEZWZhdWx0QXNzYXkoZ2JfbmVjcm9zaXMpIDwtICJOYW5vc3RyaW5nIgpWYXJpYWJsZUZlYXR1cmVzKGdiX25lY3Jvc2lzKSA8LSByb3duYW1lcyhnYl9uZWNyb3NpcykKCmdiX25lY3Jvc2lzIDwtIGdiX25lY3Jvc2lzICU+JSAKICBOb3JtYWxpemVEYXRhKCkgJT4lIAogIFNjYWxlRGF0YSgpICU+JSAKICBSdW5QQ0EoKQoKCiMjIGNsYXNzaWZ5IG5lY3Jvc2lzIGNlbGxzCmlmICghZmlsZS5leGlzdHMoZmlsZS5wYXRoKCJkYXRhIiwiR0JNXzFfMThfY2VsbHR5cGVfcHJlZGljdGlvbnMuUkRhdGEiKSkpIHsKICAgIyMgbG9hZCBhbm5vdGF0ZWQgcmVmZXJlbmNlcyBzaW5nbGUtbnVjLXNlcSBkYXRhc2V0CiAgcmVmZXJlbmNlIDwtIExvYWRINVNldXJhdChmaWxlLnBhdGgoImRhdGEiLCJyZWZlcmVuY2Vfc2V1cmF0Lkg1U2V1cmF0IikpCgogICMjIGRvd25zYW1wbGUgcmVmZXJlbmNlCiAgc2V0LnNlZWQoNzkxMDYpCiAgY2VsbF9pZHMgPC0gcmVmZXJlbmNlW1tdXSAlPiUgCiAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gImNlbGxJRCIpICU+JSAKICAgIGdyb3VwX2J5KGNlbGx0eXBlX2NvcikgJT4lIAogICAgc2xpY2Vfc2FtcGxlKG49MjAwLCByZXBsYWNlID0gVCkgJT4lIAogICAgZGlzdGluY3QoY2VsbElELCBjZWxsdHlwZV9jb3IpCiAgCiAgIyMgc3Vic2V0IGZvciBnZW5lcyBwcmVzZW50IGluIHRoZSBuYW5vc3RyaW5nIGRhdGFzZXQKICByZWZlcmVuY2UgPC0gcmVmZXJlbmNlW3Jvd25hbWVzKGdiX212cCksY2VsbF9pZHMkY2VsbElEXQogIAogICMjIHJlbW92ZSBjZWxscyB3aXRoIGZldyBjb3VudHMKICByZWZlcmVuY2UgPC0gcmVmZXJlbmNlWyxjb2xTdW1zKHJlZmVyZW5jZVtbIlJOQSJdXUBjb3VudHMpPjEwXQogIAogICMjIHJlLW5vcm1hbGl6ZQogIFZhcmlhYmxlRmVhdHVyZXMocmVmZXJlbmNlKSA8LSByb3duYW1lcyhyZWZlcmVuY2UpCiAgRGVmYXVsdEFzc2F5KHJlZmVyZW5jZSkgPC0gIlJOQSIKICByZWZlcmVuY2UgPC0gcmVmZXJlbmNlICU+JSAKICAgIE5vcm1hbGl6ZURhdGEoKSAlPiUgCiAgICBTY2FsZURhdGEoKSAlPiUgCiAgICBSdW5QQ0EoKQoKICAjIyBtYXAgY2VsbHR5cGVzCiAgYW5jaG9yc19uZWNyb3NpcyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHJlZmVyZW5jZSAsIHF1ZXJ5ID0gZ2JfbmVjcm9zaXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOjMwLCByZWZlcmVuY2UucmVkdWN0aW9uID0gInBjYSIpCiAgcHJlZGljdGlvbnNfbmVjcm9zaXMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnNfbmVjcm9zaXMsIHJlZmRhdGEgPSByZWZlcmVuY2UkY2VsbHR5cGVfY29yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1zID0gMTozMCwgay53ZWlnaHQgPSAyMCkKICAKICAjIyBhZGp1c3QgY2VsbCBsYWJlbHMKICBwcmVkaWN0aW9uc19uZWNyb3NpcyRwcmVkaWN0ZWQuaWRfY29yIDwtIGNhc2Vfd2hlbihwcmVkaWN0aW9uc19uZWNyb3NpcyRwcmVkaWN0ZWQuaWQgPT0gIlRyYW5zaXRvcnkgTW8tVEFNIiB+ICJUci4gbW9UQU1zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiTW8tVEFNIiwgcHJlZGljdGlvbnNfbmVjcm9zaXMkcHJlZGljdGVkLmlkKSB+ICJtb1RBTXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJUQU0iLCBwcmVkaWN0aW9uc19uZWNyb3NpcyRwcmVkaWN0ZWQuaWQpIH4gIm1nVEFNcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVCB+IHByZWRpY3Rpb25zX25lY3Jvc2lzJHByZWRpY3RlZC5pZCkKICAKICBzYXZlKHByZWRpY3Rpb25zX25lY3Jvc2lzLCBmaWxlID0gZmlsZS5wYXRoKCJkYXRhIiwiR0JNXzFfMThfY2VsbHR5cGVfcHJlZGljdGlvbnMuUkRhdGEiKSkKfSBlbHNlIHsKICBsb2FkKGZpbGUucGF0aCgiZGF0YSIsIkdCTV8xXzE4X2NlbGx0eXBlX3ByZWRpY3Rpb25zLlJEYXRhIikpCn0KCiMjIGFkZCBtZXRhZGF0YSAKZ2JfbmVjcm9zaXMgPC0gQWRkTWV0YURhdGEoZ2JfbmVjcm9zaXMscHJlZGljdGlvbnNfbmVjcm9zaXMpCgoKCmBgYAoKIyMjIEZpZ3VyZSA2aiBsZWZ0IHBhbmVsCmBgYHtyIEZpZ3VyZSA2aiByaWdodCwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojIyBwbG90CmNlbGxfY29scyA8LSB1bm5hbWUocGFsZXR0ZV9saWdodCgpKQpuYW1lcyhjZWxsX2NvbHMpIDwtIGMoIkFzdHJvIiwiQ0FNcyIsIkVuZG90aGVsaWFsIGNlbGxzIiwiRmlicm9ibGFzdCIsIkx5bXBob2N5dGVzIiwibWdUQU1zIiwiTXVyYWwgY2VsbHMiLCJOZXVyb24iLCJPbGlnbyIsIlR1bW9yIiwibW9UQU1zIiwiVHIuIG1vVEFNcyIpCkltYWdlRGltUGxvdChnYl9uZWNyb3NpcywgYm91bmRhcmllcyA9ICJzZWdtZW50YXRpb24iLGdyb3VwLmJ5ID0gInByZWRpY3RlZC5pZF9jb3IiLCBjb29yZC5maXhlZCA9IFQsIHNpemUgPSAxMCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNlbGxfY29sc1t1bmlxdWUoZ2JfbmVjcm9zaXMkcHJlZGljdGVkLmlkX2NvcildKQoKIyMgY2VsbHR5cGUgYmFyIHBsb3QKZ2JfbmVjcm9zaXNfbWV0YSA8LSBnYl9uZWNyb3Npc1tbXV0gJT4lIAogIGdyb3VwX2J5KHByZWRpY3RlZC5pZF9jb3IpICU+JSAKICBzdW1tYXJpc2UoY2VsbF9jb3VudD1uKCkpICU+JSAKICBtdXRhdGUodG90YWxfY2VsbHMgPSBzdW0oY2VsbF9jb3VudCksCiAgICAgICAgIGNlbGxfcGN0PXJvdW5kKGNlbGxfY291bnQvdG90YWxfY2VsbHMqMTAwLDIpLAogICAgICAgICBsYWJlbD1wYXN0ZTAocHJlZGljdGVkLmlkX2NvciwiICgiLGNlbGxfcGN0LCIlKSIpLAogICAgICAgICBDZWxsX29yZGVyZWQ9cmVvcmRlcihwcmVkaWN0ZWQuaWRfY29yLCBjZWxsX3BjdCksCiAgICAgICAgIHNlZ190b3RhbD1wYXN0ZTAoIlxuKG49Iix0b3RhbF9jZWxscywiKSIpKSAKCmBgYAoKIyMjIEZpZ3VyZSA2aiByaWdodCBwYW5lbApgYGB7ciBGaWd1cmUgNmogbGVmdCwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQojIyBwbG90IHNlZ21lbnRzCmdiX25lY3Jvc2lzIDwtIGdiX25lY3Jvc2lzICU+JSAKICBBZGRNZXRhRGF0YShyZWFkLmNzdihmaWxlLnBhdGgoImRhdGEiLCJnYl9uZWNyb3Npc19tZXRhZGF0YV9zZWdtZW50YXRpb24uY3N2IiksIHJvdy5uYW1lcz0iYmFyY29kZXMiKSkKCiMjIG1hbnVhbGx5IGFkanVzdCBzZWdtZW50YXRpb24gdG8gZm9sbG93IHRoZSBnZW5lIGV4cHJlc3Npb24gcGF0dGVybnMKc2VnbWVudGF0aW9uIDwtIGNhc2Vfd2hlbihnYl9uZWNyb3NpcyRzZWdtZW50YXRpb24gPT0gIm5vbmUiICYgR2V0VGlzc3VlQ29vcmRpbmF0ZXMoZ2JfbmVjcm9zaXMpJHkgPCAtNDQwMDAgJiBHZXRUaXNzdWVDb29yZGluYXRlcyhnYl9uZWNyb3NpcykkeCA+IC0zMjIwMDAgfiAidHVtb3IiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGdiX25lY3Jvc2lzJHNlZ21lbnRhdGlvbiA9PSAibm9uZSIgJiBHZXRUaXNzdWVDb29yZGluYXRlcyhnYl9uZWNyb3NpcykkeSA8IC00NzAwMCB+ICJ0dW1vciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2JfbmVjcm9zaXMkc2VnbWVudGF0aW9uID09ICJub25lIiAmIEdldFRpc3N1ZUNvb3JkaW5hdGVzKGdiX25lY3Jvc2lzKSR5ID4gLTQ0MDAwICYgR2V0VGlzc3VlQ29vcmRpbmF0ZXMoZ2JfbmVjcm9zaXMpJHggPCAtMzIyMDAwIH4gIm5lY3Jvc2lzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBnYl9uZWNyb3NpcyRzZWdtZW50YXRpb24gPT0gIm5vbmUiICB+ICJ0dW1vciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVCB+IGdiX25lY3Jvc2lzJHNlZ21lbnRhdGlvbiApCm5hbWVzKHNlZ21lbnRhdGlvbikgPC0gY29sbmFtZXMoZ2JfbmVjcm9zaXMpCgpnYl9uZWNyb3NpcyRzZWdtZW50YXRpb25fY29yIDwtIHNlZ21lbnRhdGlvbgoKIyMgY2VsbHR5cGUgYmFyIHBsb3QgcGVyIHNlZ21lbnRzCmdiX25lY3Jvc2lzX21ldGEgPC0gZ2JfbmVjcm9zaXNbW11dICU+JSAKICBtdXRhdGUoc2VnbWVudGF0aW9uX2Nvcj1mYWN0b3Ioc2VnbWVudGF0aW9uX2NvcixsZXZlbHM9YygidHVtb3IiLCJuZWNyb3NpcyIpKSkgJT4lIAogIGdyb3VwX2J5KHNlZ21lbnRhdGlvbl9jb3IscHJlZGljdGVkLmlkX2NvcikgJT4lIAogIHN1bW1hcmlzZShjZWxsX2NvdW50PW4oKSkgJT4lIAogIGdyb3VwX2J5KHNlZ21lbnRhdGlvbl9jb3IpICU+JSAKICBtdXRhdGUodG90YWxfY2VsbHMgPSBzdW0oY2VsbF9jb3VudCksCiAgICAgICAgIGNlbGxfcGN0PXJvdW5kKGNlbGxfY291bnQvdG90YWxfY2VsbHMqMTAwLDIpLAogICAgICAgICBsYWJlbD1wYXN0ZTAoIigiLGNlbGxfcGN0LCIlKSIpLAogICAgICAgICBzZWdfdG90YWw9cGFzdGUwKCJcbihuPSIsdG90YWxfY2VsbHMsIikiKSwKICAgICAgICAgc2VnbWVudGF0aW9uX2NvcjI9cGFzdGUwKHNlZ21lbnRhdGlvbl9jb3IsIlxuKG49Iix0b3RhbF9jZWxscywiKSIpKSAKCgpnYl9uZWNyb3Npc19tZXRhICU+JSAKICBnZ3Bsb3QoYWVzKHg9c2VnbWVudGF0aW9uX2NvciwgeT1jZWxsX3BjdCwgZmlsbD1yZW9yZGVyKHByZWRpY3RlZC5pZF9jb3IsIGNlbGxfcGN0KSwgbGFiZWwgPSBsYWJlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJzdGFjayIsIHdpZHRoID0gLjUsYWxwaGE9LjgsIGNvbG9yPSJibGFjayIsbHdkID0uMSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsNTAsMTAwKSkgKwogICNzY2FsZV9maWxsX3RxKGd1aWRlX25vbmUoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNlbGxfY29sc1t1bmlxdWUoZ2JfbmVjcm9zaXNfbWV0YSRwcmVkaWN0ZWQuaWRfY29yKV0pICsKICBnZW9tX3RleHRfcmVwZWwocG9zaXRpb24gPSBwb3NpdGlvbl9zdGFja19hbmRfbnVkZ2Uodmp1c3Q9LjUseT0zKSwgbWF4Lm92ZXJsYXBzID0gMzApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSkpICsKICAjY29vcmRfZmxpcCgpICsKICBsYWJzKHk9IkNlbGwgcGVyY2VudGFnZSBbJV0iLHg9ZWxlbWVudF9ibGFuaygpKQpgYGAKCmBgYHtyIHNvdXJjZSBkYXRhIEY2aiwgZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CmNvb3Jkc19nYiA8LSBHZXRUaXNzdWVDb29yZGluYXRlcyhnYl9uZWNyb3NpcykgCmNvb3Jkc19nYiRjZWxsdHlwZSA8LSBnYl9uZWNyb3NpcyRwcmVkaWN0ZWQuaWRfY29yCmNvb3Jkc19nYiRzZWdtZW50YXRpb24gPC0gZ2JfbmVjcm9zaXMkc2VnbWVudGF0aW9uX2NvcgoKd3JpdGUuY3N2KGNvb3Jkc19nYiwgZmlsZS5wYXRoKCJkYXRhIiwic291cmNlX2RhdGEiLCJwYW5lbF9GNmouY3N2IikpCmBgYAoKIyMjIEZpZ3VyZSA2awpgYGB7ciBGaWd1cmUgNmssIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbG9hZChmaWxlLnBhdGgoImRhdGEiLCJtdWx0aW1vZGFsX2hhcm1vbnlfaW50ZWdyYXRlZF9nYi5SRGF0YSIpKQoKYWxsIDwtIHJlZnF1ZXJ5X2htICNMb2FkSDVTZXVyYXQoZmlsZS5wYXRoKCJkYXRhIiwibXVsdGltb2RhbF9oYXJtb255X2ludGVncmF0ZWRfZ2IuSDVTZXVyYXQiKSkKcm0ocmVmcXVlcnlfaG0pCgoKIyMgY2VsbCBjeWNsZSBzY29yaW5nCnMuZ2VuZXMgPC0gY2MuZ2VuZXMkcy5nZW5lcwpnMm0uZ2VuZXMgPC0gY2MuZ2VuZXMkZzJtLmdlbmVzCgojIENyZWF0ZSBvdXIgU2V1cmF0IG9iamVjdCBhbmQgY29tcGxldGUgdGhlIGluaXRhbGl6YXRpb24gc3RlcHMKYWxsIDwtIENlbGxDeWNsZVNjb3JpbmcoYWxsLCBzLmZlYXR1cmVzID0gcy5nZW5lcywgZzJtLmZlYXR1cmVzID0gZzJtLmdlbmVzKQpjY19zY29yZXMgPC0gU2NvcmVTaWduYXR1cmVzX1VDZWxsKGFsbFtbIlJOQSJdXUBjb3VudHMsIGZlYXR1cmVzPWxpc3Qocy5mZWF0dXJlcyA9IHMuZ2VuZXMsIGcybS5mZWF0dXJlcyA9IGcybS5nZW5lcykpCmFsbCA8LSBBZGRNZXRhRGF0YShhbGwsIGFzLmRhdGEuZnJhbWUoY2Nfc2NvcmVzKSkKCiMjIGFkanVzdCBjbHVzdGVyIG9yZGVyCm9yZGVyX2NsdXN0ZXJzIDwtIGRhdGEuZnJhbWUoc2V1cmF0X2NsdXN0ZXJzPSBhbGwkc2V1cmF0X2NsdXN0ZXJzLCByb3cubmFtZXMgPSByb3duYW1lcyhhbGxbW11dKSkgJT4lCiAgYmluZF9jb2xzKGFzLmRhdGEuZnJhbWUodChhbGxbWyJSTkEiXV1Ac2NhbGUuZGF0YSkpKSAlPiUKICBncm91cF9ieShzZXVyYXRfY2x1c3RlcnMpICU+JQogIHN1bW1hcml6ZV9hbGwoLmZ1bnM9bWVhbikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCgojIyBhZGp1c3QgY2x1c3RlciBvcmRlcgpvcmRlcl9jbHVzdGVycyA8LSBkYXRhLmZyYW1lKHNldXJhdF9jbHVzdGVycz0gYWxsJHNldXJhdF9jbHVzdGVycywgcm93Lm5hbWVzID0gcm93bmFtZXMoYWxsW1tdXSkpICU+JQogIGJpbmRfY29scyhhcy5kYXRhLmZyYW1lKHQoYWxsW1siUk5BIl1dQHNjYWxlLmRhdGEpKSkgJT4lCiAgZ3JvdXBfYnkoc2V1cmF0X2NsdXN0ZXJzKSAlPiUKICBzdW1tYXJpemVfYWxsKC5mdW5zPW1lYW4pICU+JQogIGFzLmRhdGEuZnJhbWUoKQpyb3duYW1lcyhvcmRlcl9jbHVzdGVycykgPC0gb3JkZXJfY2x1c3RlcnMkc2V1cmF0X2NsdXN0ZXJzCm9yZGVyX2NsdXN0ZXJzIDwtIG9yZGVyX2NsdXN0ZXJzJHNldXJhdF9jbHVzdGVyc1toY2x1c3QoZGlzdChvcmRlcl9jbHVzdGVyc1ssLTFdKSkkb3JkZXJdCgpsZXZlbHMoYWxsKSA8LSByZXYob3JkZXJfY2x1c3RlcnMpW2MoMTIsMTQsMTMsMTU6MzAsMTE6MSldCgojIyBhZGp1c3QgY2VsbCB0eXBlcwpjZWxsdHlwZV9jb3IgPC0gY2FzZV93aGVuKAogIGFsbCRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKCIxOSIsIjI5IikgfiAiTmV1cm9lY3RvZGVybWFsIiwKICBhbGwkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygiMTciKSB+ICJDQU1zIiwKICBhbGwkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygiMyIsIjciLCIxMSIsIjE0IiwiMTYiLCIwIiwiMTIiLCIxIiwiNSIpIH4gIk1HIiwKICBhbGwkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygiMTUiKSAmIGFsbCRkaWFnbm9zaXMgPT0gIkdCIiB+ICJUcmFucy4gbW9UQU1zIiwKICBhbGwkc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygiMiIsIjQiKSAmIGFsbCRkaWFnbm9zaXMgPT0gIkdCIiB+ICJUQU1zIiwKICAjYWxsJHNldXJhdF9jbHVzdGVycyAlaW4lIGMoIjIiKSAmIGFsbCRkaWFnbm9zaXMgPT0gIkdCIiB+ICJtZ1RBTXMiLAogIGFsbCRzZXVyYXRfY2x1c3RlcnMgJWluJSBjKCI4IikgfiAiQ2xhc3MuIE1vbm8iLAogIGFsbCRwcmVkaWN0ZWQuY2VsbHR5cGUgPT0gIkNEMTQgTW9ubyIgfiAiQ2xhc3MuIE1vbm8iLAogIGFsbCRwcmVkaWN0ZWQuY2VsbHR5cGUgPT0gIkNEMTYgTW9ubyIgJiBhbGwkc2V1cmF0X2NsdXN0ZXJzID09ICgiMjMiKSB+ICJOb24tQ2xhc3MuIE1vbm8iLAogIFQgfiBhbGwkcHJlZGljdGVkLmNlbGx0eXBlCikKCm5hbWVzKGNlbGx0eXBlX2NvcikgPC0gY29sbmFtZXMoYWxsKQphbGwkY2VsbHR5cGVfY29yIDwtIGNlbGx0eXBlX2NvcgoKIyMgcnVuIGFkdCBhbmFseXNpcwphbGxfYWR0IDwtIGFsbApEZWZhdWx0QXNzYXkoYWxsX2FkdCkgPC0gIkFEVCIKClZhcmlhYmxlRmVhdHVyZXMoYWxsX2FkdCkgPC0gcm93bmFtZXMoYWxsX2FkdCkKYWxsX2FkdCA8LSBhbGxfYWR0ICU+JSAKICBzdWJzZXQoc3Vic2V0ID0gbkNvdW50X0FEVCA+IDUwKSAlPiUgICMgICU+JSAKICBOb3JtYWxpemVEYXRhKG5vcm1hbGl6YXRpb24ubWV0aG9kID0gJ0NMUicsIG1hcmdpbiA9IDIpICU+JSAKICBTY2FsZURhdGEodmFycy50by5yZWdyZXNzID0gIm5Db3VudF9BRFQiKSAlPiUgCiAgUnVuUENBKHJlZHVjdGlvbi5uYW1lID0gJ2FwY2EnKQoKIyMgc2V0IGNvbXBvc2l0ZSBjZWxsdHlwZXMKY29tcG9zaXRlX2NlbGx0eXBlIDwtIHBhc3RlKGFsbF9hZHQkY29tcGFydG1lbnQsIGFsbF9hZHQkZGlhZ25vc2lzLCBhbGxfYWR0JGNlbGx0eXBlX2NvcixzZXA9Il8iKQoKY29tcG9zaXRlX2NlbGx0eXBlW2dyZXBsKCIoTUd8bWcpIixjb21wb3NpdGVfY2VsbHR5cGUpXSA8LSBnc3ViKCIoTE1ffENUWF8pIiwiIixjb21wb3NpdGVfY2VsbHR5cGVbZ3JlcGwoIihNR3xtZykiLGNvbXBvc2l0ZV9jZWxsdHlwZSldKQoKbmFtZXMoY29tcG9zaXRlX2NlbGx0eXBlKSA8LSBjb2xuYW1lcyhhbGxfYWR0KQphbGxfYWR0JGNvbXBvc2l0ZV9jZWxsdHlwZSA8LSBjb21wb3NpdGVfY2VsbHR5cGUKCmFsbF9hZHRfbXllbG9pZCA8LSBhbGxfYWR0WyxncmVwbCgiKE1HfFRBTXxDQU1zKSIsIGFsbF9hZHQkY29tcG9zaXRlX2NlbGx0eXBlKV0KCklkZW50cyhhbGxfYWR0X215ZWxvaWQpIDwtIGFsbF9hZHRfbXllbG9pZCRjb21wb3NpdGVfY2VsbHR5cGUKCiMjIGJvdGggY29tcGFydG1lbnRzCiMjIGRpZmZlcmVudGlhbCBnZW5lcyBwZXIgY29tcGFydG1lbnQKbXllbG9pZF9hZHRfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhhbGxfYWR0X215ZWxvaWQsbG9nZmMudGhyZXNob2xkPS4yKSAKdG9wNSA8LSBteWVsb2lkX2FkdF9tYXJrZXJzICU+JSAKICBmaWx0ZXIocF92YWxfYWRqPC4wNSAmIGF2Z19sb2cyRkM+MCkgJT4lIAogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICB0b3Bfbig1LCB3dD1hdmdfbG9nMkZDKSAKCm1lYW5fZXhwciA8LSBkYXRhLmZyYW1lKHQoYXMubWF0cml4KGFsbF9hZHRfbXllbG9pZFtbIkFEVCJdXUBkYXRhW3VuaXF1ZSh0b3A1JGdlbmUpLF0pKSwgImNsdXN0ZXIiPWFsbF9hZHRfbXllbG9pZCRjb21wb3NpdGVfY2VsbHR5cGUpICU+JSAgCiAgZmlsdGVyKGNsdXN0ZXIgIT0gIkNUWF9DdHJsX0NBTXMiKSAlPiUgIyMjIGV4Y2x1ZGUgY3RybCBjYW1zIGJlY2F1c2UgdGhleSB3ZXJlIHNvIGZldwogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICBzdW1tYXJpc2VfYWxsKC5mdW5zID0gbWVhbikgJT4lIAogIGFzLmRhdGEuZnJhbWUoKQoKcm93bmFtZXMobWVhbl9leHByKSA8LSBtZWFuX2V4cHIkY2x1c3RlcgptZWFuX2V4cHIkY2x1c3RlciA8LSBOVUxMCnByb3RzIDwtIGdzdWIoIihIdVxcLnxcXC5NNUUyfEh1TXNcXC58X1JQQV9UNCkiLCIiLGNvbG5hbWVzKG1lYW5fZXhwcikpCnByb3RzIDwtIGdzdWIoIihcXC4pIiwiXyIscHJvdHMpCmNvbG5hbWVzKG1lYW5fZXhwcikgPC0gcHJvdHMKbWF0IDwtIHNjYWxlKGFzLm1hdHJpeChtZWFuX2V4cHIpKQoKIyMgYWRkIHJvdyBhbm5vdGF0aW9uIApyb3dfYW5ucyA8LSBtYXQgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInNhbXBsZSIpICU+JSAKICBtdXRhdGUoY29tcGFydG1lbnQgPSBpZmVsc2UoZ3JlcGwoIk1HIixzYW1wbGUpLCJDVFgiLGdzdWIoIl8uKiIsIiIsc2FtcGxlKSksCiAgICAgICAgIGRpYWdub3NpcyA9IGlmZWxzZShncmVwbCgiR0IiLHNhbXBsZSksICJHQiIsIkN0cmwiKSkgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygic2FtcGxlIikKCnJvd19oYSA8LSByb3dBbm5vdGF0aW9uKGNvbXBhcnRtZW50ID0gcm93X2FubnMkY29tcGFydG1lbnQsCiAgICAgICAgICAgICAgICAgICAgICAgIGRpYWdub3NpcyA9IHJvd19hbm5zJGRpYWdub3NpcywKICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChjb21wYXJ0bWVudCA9IGMoIkxNIiA9IHVubmFtZShwYWxldHRlX2RhcmsoKSlbNF0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNUWCIgPSB1bm5hbWUocGFsZXR0ZV9kYXJrKCkpWzJdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlhZ25vc2lzID0gIGMoIkN0cmwiID0gdW5uYW1lKHBhbGV0dGVfZ3JlZW4oKSlbYyg1KV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHQiIgPSB1bm5hbWUocGFsZXR0ZV9ncmVlbigpKVtjKDcpXSkpLAogICAgICAgICAgICAgICAgICAgICAgICBnYXAgPSB1bml0KDIuNSwgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlciA9IFRSVUUpCgpIZWF0bWFwKG1hdCwgY2x1c3Rlcl9yb3dzID0gVCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBULCAKICAgICAgICAjcmlnaHRfYW5ub3RhdGlvbiA9IHJvd19oYSwKICAgICAgICBjbHVzdGVyaW5nX21ldGhvZF9yb3dzID0gIndhcmQuRDIiLAogICAgICAgIHdpZHRoID0gbmNvbChtYXQpKnVuaXQoNSwgIm1tIiksIAogICAgICAgIGhlaWdodCA9IG5yb3cobWF0KSp1bml0KDUsICJtbSIpKQpgYGAKCmBgYHtyIHNvdXJjZSBkYXRhIEY2aywgZWNobz1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CndyaXRlLmNzdihtYXQsIGZpbGUucGF0aCgiZGF0YSIsInNvdXJjZV9kYXRhIiwicGFuZWxfRjZrLmNzdiIpKQpgYGAKCgpSb21hbiBTYW5rb3dza2kKMDMtMTAtMjAyMwplbWFpbDogcm9tYW4uc2Fua293c2tpQHVuaWtsaW5pay1mcmVpYnVyZy5kZQo=